#ifndef __case_gpio_kenny_kfjiweiiur89u83r33e3e__
#define __case_gpio_kenny_kfjiweiiur89u83r33e3e__

#include <future>

#include <hude/base/log.hpp>
#include <hude/aio/context.hpp>

#include "test/test.hpp"

#include "brick/brick.hpp"
#include "plugs/virt-gpio/virt-gpio.hpp"

namespace test
{
    using namespace ha;

    //--------------------------------------------------------------------------------
    struct case_gpio_t : public hude::test::case_t
    {
        enum { emCOUNT };

        using pkg_t = brick::pkg_gpio_t;

        // 测试过程
        bool run() override;
    };

    //--------------------------------------------------------------------------------
    inline bool case_gpio_t::run()
    {
        factory_brick_t::plug_t plug{ "./build-debug/lib/libvirt-gpio.so" };

        if( ! plug )
        {
            log_err( "ERROR: load plug: gpio" );
            return false;
        } else {
            log_inf( "SUCCESS: load factory( gpio )" );
        }

        auto cfg  = hude::utils::json_t{};
        auto gpio = plug( hude::aio::context_t<>::aio(), cfg );

        if( ! gpio )
        {
            log_err( "ERROR: production gpio instance." );
            return false;
        }

        std::promise< hude::buffer_t > pm;

        gpio->cb_recv( [&]( const hude::buffer_t& buffer ) {
            if( buffer.empty() )
            {
                log_war( "\t recv index( %d ) empty buffer{}" );
            } else {
                log_nte( "\t recv <<< buffer{ %s }", hude::utils::to_hex( buffer ).c_str() );
            }

            pm.set_value( std::move( buffer ) );
        } );

        auto sync = [&]( uint8_t pin, pkg_t::cmd_t c,
            pkg_t::value_t v = pkg_t::value_t::emVL, pkg_t::direction_t d = pkg_t::direction_t::emDIN )
        {
            pkg_t cmd( 0U, pin, v, d, c );

            auto p = (const uint8_t*)&cmd;
            hude::buffer_t buffer{ p, p + pkg_t::emSIZ_PKG };

            log_inf( "\t send >>> buffer{ %s }", hude::utils::to_hex( buffer ).c_str() );

            pm = std::promise< hude::buffer_t >{};

            gpio->send( &(buffer[0]), buffer.size() );

            auto f = pm.get_future();

            if( f.wait_for( std::chrono::seconds( 1 ) ) == std::future_status::ready )
            {
                auto ret = f.get();
                auto pkg = (const pkg_t*)&(ret[0]);

                log_dug( "\t\t { pin: %u, cmd: %u, dir: %u, val: %u, ret: %u }",
                    pkg->gpio.ident.index,
                    pkg->gpio.command,
                    pkg->gpio.direction,
                    pkg->gpio.value,
                    pkg->gpio.result );

                return pkg->gpio.result == 0 && ( (c == pkg_t::cmd_t::emCMD_SET)? pkg->gpio.value == v : true );
            } else {
                log_err( "\t request timeout." );
            }

            return false;
        };

        bool ret = true;

        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_OPEN, pkg_t::value_t::emVL, pkg_t::direction_t::emDOUT );
        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_GET );
        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_SET, pkg_t::value_t::emVH );
        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_GET );
        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_SET, pkg_t::value_t::emVL );
        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_GET );

        ret = ret && ( ! sync( 11U, pkg_t::cmd_t::emCMD_OPEN ) );
        ret = ret && ( ! sync( 12U, pkg_t::cmd_t::emCMD_GET ) );
        ret = ret && ( ! sync( 12U, pkg_t::cmd_t::emCMD_SET, pkg_t::value_t::emVH ) );
        ret = ret && ( ! sync( 12U, pkg_t::cmd_t::emCMD_CLOSE ) );

        ret = ret && sync( 11U, pkg_t::cmd_t::emCMD_CLOSE );

        return ret;
    }

    TEST_CASE_ADD( "case-gpio", case_gpio_t, false );

} // namespace test

#endif // __case_gpio_kenny_kfjiweiiur89u83r33e3e__


